package com.bluexmicro.android.upgradebox.screen.configure

import android.content.Context
import android.util.Log
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringSetPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.ViewModelFactoryDsl
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import java.io.File
import java.math.BigInteger

data class Resource(
    val file: File,
    val address: BigInteger?
) {
    var rawData = ByteArray(0)
}

val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")


class ConfigVMFactory(
    private val context: Context
) : ViewModelProvider.Factory {

    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return ConfigureViewModel(context.dataStore) as T
    }
}

/**
 *
 */
class ConfigureViewModel(
    private val dataStore: DataStore<Preferences>
) : ViewModel() {

    val resources = mutableStateListOf<Resource>()

    val nameFilters = mutableStateListOf<String>()
    val companyIdFilters = mutableStateListOf<String>()
    val macFilters = mutableStateListOf<String>()

    val rssiThreshold = mutableStateOf(0f)//-127+127 = 0 -50+127=77,范围：0~127

    ///////////////////////////////////////////////////////////////////////////
    //
    ///////////////////////////////////////////////////////////////////////////

    /**
     * 第一次启动时加载
     * LaunchEffect
     */
    fun onLoad() {
        Log.e("TAG", "onLoad: ")
        viewModelScope.launch(Dispatchers.IO) {
            resources.addAll(loadResourcesFlow().first())
            nameFilters.addAll(loadNameFilterFlow().first())
            companyIdFilters.addAll(loadCompanyFilterFlow().first())
            macFilters.addAll(loadMacFiltersFlow().first())
            rssiThreshold.value = loadRssiThresholdFlow().first().toFloat()
        }
    }

    private val resourcesKey = stringSetPreferencesKey("resources")
    private val nameFilterKey = stringSetPreferencesKey("nameFilter")
    private val macFilterKey = stringSetPreferencesKey("macFilter")
    private val companyFilterKey = stringSetPreferencesKey("companyFilter")
    private val rssiFilterKey = intPreferencesKey("rssiFilter")

    private fun loadResourcesFlow(): Flow<List<Resource>> =
        dataStore.data.map {
            val sets = mutableListOf<Resource>()
            it[resourcesKey]?.forEach { formatRes ->
                //"path|hexAddress?"
                val params = formatRes.split('|')
                val file = if (0 in params.indices) {
                    File(params[0])
                } else {
                    null
                }
                val address = if (1 in params.indices) {
                    try {
                        BigInteger(params[1], 16)
                    } catch (e: Exception) {
                        e.printStackTrace()
                        null
                    }
                } else {
                    null
                }
                if (file != null) {
                    sets.add(Resource(file, address))
                }
            }
            sets
        }

    private fun loadCompanyFilterFlow(): Flow<List<String>> =
        dataStore.data.map {
            val sets = mutableListOf<String>()
            it[companyFilterKey]?.forEach { companyIdHex ->
                //todo 有效性检查
                sets.add(companyIdHex)
            }
            sets
        }

    private fun loadNameFilterFlow(): Flow<List<String>> =
        dataStore.data.map {
            val sets = mutableListOf<String>()
            it[nameFilterKey]?.forEach { name ->
                sets.add(name)
            }
            sets
        }

    private fun loadMacFiltersFlow(): Flow<List<String>> =
        dataStore.data.map {
            val sets = mutableListOf<String>()
            it[macFilterKey]?.forEach { mac ->
                sets.add(mac)
            }
            sets
        }

    /**
     * [0,127]
     */
    private fun loadRssiThresholdFlow(): Flow<Int> =
        dataStore.data.map {
            it[rssiFilterKey] ?: -127
        }

    ///////////////////////////////////////////////////////////////////////////
    //
    ///////////////////////////////////////////////////////////////////////////

    fun onFileSelected(file: File, address: BigInteger?) = viewModelScope.launch(Dispatchers.IO) {
        var index = -1
        for (withIndex in resources.withIndex()) {
            if (withIndex.value.file.path == file.path) {
                index = withIndex.index
                break
            }
        }
        val res = Resource(file, address)
        if (index in resources.indices) {
            resources[index] = res
        } else {
            resources.add(res)
        }

        val sets = resources.map {
            "${it.file.path}|${it.address?.toString(16)}"
        }

        dataStore.edit {
            it[resourcesKey] = sets.toSet()
        }
    }

    fun onResourceRemoved(res: Resource) = viewModelScope.launch(Dispatchers.IO) {
        resources.remove(res)
        val sets = resources.map {
            "${it.file.path}|${it.address?.toString(16)}"
        }

        dataStore.edit {
            it[resourcesKey] = sets.toSet()
        }
    }

    fun addMacFilter(macFilter: String) = viewModelScope.launch(Dispatchers.IO) {
        if (!macFilters.contains(macFilter)) {
            macFilters.add(macFilter)
        }
        dataStore.edit {
            it[macFilterKey] = macFilters.toSet()
        }
    }

    fun removeMacFilter(macFilter: String) = viewModelScope.launch(Dispatchers.IO) {
        macFilters.remove(macFilter)
        dataStore.edit {
            it[macFilterKey] = macFilters.toSet()
        }
    }

    fun addCompanyFilter(companyId: String) = viewModelScope.launch(Dispatchers.IO) {
        if (!companyIdFilters.contains(companyId)) {
            companyIdFilters.add(companyId)
        }
        dataStore.edit {
            it[companyFilterKey] = companyIdFilters.toSet()
        }
    }

    fun removeCompanyFilter(companyId: String) = viewModelScope.launch(Dispatchers.IO) {
        companyIdFilters.remove(companyId)
        dataStore.edit {
            it[companyFilterKey] = companyIdFilters.toSet()
        }
    }

    fun addNameFilter(nameFilter: String) = viewModelScope.launch(Dispatchers.IO) {
        if (!nameFilters.contains(nameFilter)) {
            nameFilters.add(nameFilter)
        }
        dataStore.edit {
            it[nameFilterKey] = nameFilters.toSet()
        }
    }

    fun removeNameFilter(nameFilter: String) = viewModelScope.launch(Dispatchers.IO) {
        nameFilters.remove(nameFilter)
        dataStore.edit {
            it[nameFilterKey] = nameFilters.toSet()
        }
    }

    fun saveRssi() = viewModelScope.launch(Dispatchers.IO) {
        dataStore.edit {
            it[rssiFilterKey] = rssiThreshold.value.toInt()
        }
    }


}